/****************************************************************************
 *
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/


/**
 *  @file
 *  @author Gus Grubba <gus@auterion.com>
 */

#ifndef QGC_MAP_URL_ENGINE_H
#define QGC_MAP_URL_ENGINE_H


#include "GoogleMapProvider.h"
#include "BingMapProvider.h"
#include "GenericMapProvider.h"
#include "EsriMapProvider.h"
#include "MapboxMapProvider.h"
#include "ElevationMapProvider.h"

#define MAX_MAP_ZOOM (23.0)

/**
 * @brief 地图URL工厂类
 * 
 * UrlFactory是地图系统的核心工厂类，负责管理和协调各种地图提供商，
 * 提供统一的接口来生成地图瓦片URL、处理地图类型转换、坐标计算等功能。
 * 
 * 主要职责包括：
 * 1. 管理所有支持的地图提供商实例
 * 2. 根据地图类型和坐标生成瓦片URL请求
 * 3. 处理地图类型与ID之间的转换
 * 4. 提供图像格式识别功能
 * 5. 执行地理坐标与瓦片坐标的转换计算
 * 6. 计算指定区域的瓦片数量
 */
class UrlFactory : public QObject {
    Q_OBJECT
public:
    /**
     * @brief Copernicus高程提供商键名
     */
    static const char* kCopernicusElevationProviderKey;
    
    /**
     * @brief Copernicus高程提供商版权声明
     */
    static const char* kCopernicusElevationProviderNotice;

    /**
     * @brief 构造函数
     * 初始化URL工厂，设置默认超时时间并注册地图提供商
     */
    UrlFactory      ();
    
    /**
     * @brief 析构函数
     * 清理资源
     */
    ~UrlFactory     ();

    /**
     * @brief 根据地图类型获取瓦片URL请求
     * @param type 地图类型名称
     * @param x 瓦片X坐标
     * @param y 瓦片Y坐标
     * @param zoom 缩放级别
     * @param networkManager 网络管理器
     * @return QNetworkRequest 网络请求对象
     */
    QNetworkRequest getTileURL          (const QString& type, int x, int y, int zoom, QNetworkAccessManager* networkManager);
    
    /**
     * @brief 根据地图ID获取瓦片URL请求
     * @param id 地图类型ID
     * @param x 瓦片X坐标
     * @param y 瓦片Y坐标
     * @param zoom 缩放级别
     * @param networkManager 网络管理器
     * @return QNetworkRequest 网络请求对象
     */
    QNetworkRequest getTileURL          (int id, int x, int y, int zoom, QNetworkAccessManager* networkManager);

    /**
     * @brief 根据地图类型识别图像格式
     * @param type 地图类型名称
     * @param image 图像数据
     * @return QString 图像格式（如png、jpg等）
     */
    QString         getImageFormat      (const QString& type, const QByteArray& image);
    
    /**
     * @brief 根据地图ID识别图像格式
     * @param id 地图类型ID
     * @param image 图像数据
     * @return QString 图像格式（如png、jpg等）
     */
    QString         getImageFormat      (int id , const QByteArray& image);

    /**
     * @brief 获取指定地图类型的平均瓦片大小
     * @param type 地图类型名称
     * @return quint32 平均瓦片大小（字节）
     */
    quint32  averageSizeForType  (const QString& type);

    /**
     * @brief 将经度转换为瓦片X坐标
     * @param mapType 地图类型名称
     * @param lon 经度
     * @param z 缩放级别
     * @return int 瓦片X坐标
     */
    int long2tileX(const QString& mapType, double lon, int z);
    
    /**
     * @brief 将纬度转换为瓦片Y坐标
     * @param mapType 地图类型名称
     * @param lat 纬度
     * @param z 缩放级别
     * @return int 瓦片Y坐标
     */
    int lat2tileY(const QString& mapType, double lat, int z);

    /**
     * @brief 获取地图提供商表
     * @return QHash<QString, MapProvider*> 地图提供商哈希表
     */
    QHash<QString, MapProvider*> getProviderTable(){return _providersTable;}

    /**
     * @brief 根据地图类型获取地图ID
     * @param type 地图类型名称
     * @return int 地图类型ID
     */
    int getIdFromType(const QString& type);
    
    /**
     * @brief 根据地图ID获取地图类型名称
     * @param id 地图类型ID
     * @return QString 地图类型名称
     */
    QString getTypeFromId(int id);
    
    /**
     * @brief 根据地图ID获取地图提供商实例
     * @param id 地图类型ID
     * @return MapProvider* 地图提供商实例指针
     */
    MapProvider* getMapProviderFromId(int id);

    /**
     * @brief 计算指定区域的瓦片数量
     * @param zoom 缩放级别
     * @param topleftLon 左上角经度
     * @param topleftLat 左上角纬度
     * @param bottomRightLon 右下角经度
     * @param bottomRightLat 右下角纬度
     * @param mapType 地图类型名称
     * @return QGCTileSet 瓦片集信息
     */
    QGCTileSet getTileCount(int zoom, double topleftLon, double topleftLat,
                            double bottomRightLon, double bottomRightLat,
                            const QString& mapType);

    /**
     * @brief 判断地图是否为高程图
     * @param mapId 地图ID
     * @return bool 是否为高程图
     */
    bool isElevation(int mapId);

  private:
    int             _timeout;                 ///< 网络请求超时时间（毫秒）
    QHash<QString, MapProvider*> _providersTable; ///< 地图提供商哈希表，键为地图类型名称，值为地图提供商实例
    /**
     * @brief 注册地图提供商
     * @param Name 地图提供商名称
     * @param provider 地图提供商实例
     */
    void registerProvider(QString Name, MapProvider* provider);

};

#endif